package com.hooya.fa.eu.biz.dao.manager.special;

import com.hooya.fa.eu.api.bo.stk.HistoryBelongsBO;
import com.hooya.fa.eu.api.bo.stk.SellRecordBO;
import com.hooya.fa.eu.api.enums.CkEnum;
import com.hooya.fa.eu.biz.dao.entity.PlaceMatchDict;
import com.hooya.fa.eu.biz.dao.mapper.StkSellMapper;
import com.hooya.fa.eu.biz.dao.mapper.stk.TempXsjlMapper;
import com.hooya.fa.eu.biz.service.EuSourceDataService;
import com.hooya.integrated.common.core.util.RedisUtils;
import com.xxl.job.core.context.XxlJobHelper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.hooya.fa.eu.api.constant.DictConstant.DICT_PREFIX;

/**
 * @Description 销售发货
 * @Author : Zongz
 * @Copyright Copyright (c) 豪雅集团
 * @Create 2024/3/7
 * @Version 1.0.0
 */
@Slf4j
@Component
@AllArgsConstructor
public class SellDeliveryManager {

	private final EuSourceDataService euSourceDataService;

	private final TempXsjlMapper tempXsjlMapper;

	private final StkSellMapper stkSellMapper;

	/**
	 * 处理当天的销售数据
	 *
	 * @param curDate              日期
	 * @param sellDeliveryList     销售数据
	 * @param newAllHisBelongsList 历史货权
	 * @return 销售数据结果
	 */
	public List<SellRecordBO> dealCurSellDelivery(String curDate, List<SellRecordBO> sellDeliveryList,
												  List<HistoryBelongsBO> newAllHisBelongsList) {
		Set<String> sfCkList = RedisUtils.sGet(DICT_PREFIX + CkEnum.SF_CK_LIST.getName());
		Map<String, List<String>> countryCkMap = RedisUtils.hmget(DICT_PREFIX + CkEnum.COUNTRY_CK_MAP.getName());
		Map<String, List<String>> fbaCkFdsMap = new TreeMap<>(RedisUtils.hmget(DICT_PREFIX + CkEnum.FBA_CK_REVERSAL_MAP.getName()));
		List<SellRecordBO> curSellData = sellDeliveryList.stream()
				.filter(l -> l.getOrderDate().equals(curDate) && (
						l.getRestockMark().equals("") || l.getRestockMark().equals("restock") ||
								l.getRestockMark().equals("SFA") || fbaCkFdsMap.containsKey(l.getRestockMark())
				)).collect(Collectors.toList());
		curSellData.stream().filter(l -> l.getLywl().contains("SFA") && !l.getRestockMark().equals("SFA")
				&& l.getFromCountry().equals("PL")).forEach(l -> {
			l.setLywl("");
			XxlJobHelper.log(l.getSheetNumber() + "__物流信息置空__" + l.getOrderId());
			log.info(l.getSheetNumber() + "__物流信息置空__" + l.getOrderId());
		});
		curSellData.stream().filter(l -> l.getLywl().contains("SFA") && !l.getRestockMark().equals("SFA"))
				.forEach(l -> {
					String newPlace = sfCkList.stream()
							.filter(place -> countryCkMap.get(l.getFromCountry()).contains(place) &&
									newAllHisBelongsList.stream().anyMatch(h -> h.getCpbh().equals(l.getCpbh()) &&
											h.getPlace().equals(place))).findFirst().orElse("");
					if (StringUtils.isBlank(newPlace)) {
						throw new RuntimeException("出货地为空");
					}
					curSellData.stream().filter(m -> m.getSheetNumber().equals(l.getSheetNumber()))
							.forEach(m -> {
								m.setChck(newPlace);
								m.setRestockMark("SFA");
							});
				});
		return curSellData;
	}

	/**
	 * 根据时间获取销售发货数据
	 *
	 * @param startDate         开始时间
	 * @param endDate           结束时间
	 * @param placeMatchDictMap 仓库匹配字段map
	 * @param storeMap          店铺map
	 * @param fbaCountryList    fba国家列表
	 * @return list
	 */
	public List<SellRecordBO> getSellDeliveryListByDate(String startDate, String endDate, Map<String,
			PlaceMatchDict> placeMatchDictMap, Map<String, String> storeMap, List<String> fbaCountryList) {
		//销售发货数据包含 fba（物流信息包含fba，仅有销售数据），非fba（物流信息不包含fba，既有只有销售部分的数据，又有销售和发货信息的数据）
		List<SellRecordBO> sellDeliveryList = new LinkedList<>();
		//fba销售记录
		List<SellRecordBO> sellRecordList = euSourceDataService.getSellRecordListByDate(startDate, endDate);  // TODO - 数据源待修改 europe.xsjl_2303
		//获取whId，用于优化发货sql
		List<String> whIds = euSourceDataService.getWhIdByTimeGet(startDate, endDate);  // TODO - 数据源待修改 europe.ck deliver_goods
		//有发货的销售记录
		//（由发货记录进行反查，精确定位数据。会有一种情况：发货记录同步进来，但是销售记录不存在，因为种种原因
		//销售记录的金额是0(但领导不愿看到这种数据，所以不刷写进来)。现有数据由2种情况组成。
		// 1：发货数据进来了，原始的销售记录的金额也存在，但是数据没刷进来。解决方案：及时通知同步即可
		// 2：当月下，发货数据为本月且进来了，但原始数据的销售记录的金额不存在。解决方案：未定）。
		//发货记录为什么使用反查方式处理？
		//后续在每日循环中，是根据orderDate进行筛选，
		//未发货的orderDate就是销售记录的orderDate，发货的orderDate是发货记录中的date。
		List<SellRecordBO> deliveryGoodsList = euSourceDataService  // TODO - 数据源待修改 europe.deliver_goods deliver_goodssheet xsjl_2303
				.getDeliveryGoodsListByDate(startDate, endDate, whIds);
		//删选符合条件的销售数据
		this.getEligibleSellDeliveryData(sellRecordList, deliveryGoodsList,
				sellDeliveryList, placeMatchDictMap, storeMap, fbaCountryList);
		return sellDeliveryList.stream().distinct().filter(l -> !l.getChck().equals("EU07"))
				.collect(Collectors.toList());
	}

	public List<SellRecordBO> getSellDeliveryListByDateDaily(String startDate, String endDate, Map<String,
			PlaceMatchDict> placeMatchDictMap, Map<String, String> storeMap, List<String> fbaCountryList) {
		//销售发货数据包含 fba（物流信息包含fba，仅有销售数据），非fba（物流信息不包含fba，既有只有销售部分的数据，又有销售和发货信息的数据）
		List<SellRecordBO> sellDeliveryList = new LinkedList<>();
		//fba销售记录
		List<SellRecordBO> sellRecordList = stkSellMapper.getSellRecordListByDateDaily(startDate, endDate);  // TODO - 数据源待修改 europe.xsjl_2303
		//获取whId，用于优化发货sql
		List<String> whIds = stkSellMapper.getWhIdByTimeGetDaily(startDate, endDate);  // TODO - 数据源待修改 europe.ck deliver_goods
		//有发货的销售记录
		//（由发货记录进行反查，精确定位数据。会有一种情况：发货记录同步进来，但是销售记录不存在，因为种种原因
		//销售记录的金额是0(但领导不愿看到这种数据，所以不刷写进来)。现有数据由2种情况组成。
		// 1：发货数据进来了，原始的销售记录的金额也存在，但是数据没刷进来。解决方案：及时通知同步即可
		// 2：当月下，发货数据为本月且进来了，但原始数据的销售记录的金额不存在。解决方案：未定）。
		//发货记录为什么使用反查方式处理？
		//后续在每日循环中，是根据orderDate进行筛选，
		//未发货的orderDate就是销售记录的orderDate，发货的orderDate是发货记录中的date。
		List<SellRecordBO> deliveryGoodsList = stkSellMapper  // TODO - 数据源待修改 europe.deliver_goods deliver_goodssheet xsjl_2303
				.getDeliveryGoodsListByDateDaily(startDate, endDate, whIds);
		//删选符合条件的销售数据
		this.getEligibleSellDeliveryData(sellRecordList, deliveryGoodsList,
				sellDeliveryList, placeMatchDictMap, storeMap, fbaCountryList);
		return sellDeliveryList.stream().distinct().filter(l -> !l.getChck().equals("EU07"))
				.collect(Collectors.toList());
	}

	/**
	 * 筛选符合条件的销售发货数据
	 *
	 * @param sellRecordList    销售记录数据
	 * @param deliveryGoodsList 发货数据（含销售）
	 * @param sellDeliveryList  销售发货结果集
	 * @param placeMatchDictMap place匹配字典
	 * @param storeMap          商铺字典
	 * @param fbaCountryList    fba国家列表
	 */
	public void getEligibleSellDeliveryData(List<SellRecordBO> sellRecordList,
											List<SellRecordBO> deliveryGoodsList,
											List<SellRecordBO> sellDeliveryList,
											Map<String, PlaceMatchDict> placeMatchDictMap,
											Map<String, String> storeMap, List<String> fbaCountryList) {
		//字典数据
		Map<String, String> oeuOrderMap = RedisUtils.hmget(DICT_PREFIX + CkEnum.OEU_ORDER_MAP.getName());
		Set<String> fbaWlList = RedisUtils.sGet(DICT_PREFIX + CkEnum.FBA_WL_LIST.getName());
		//取fba数据
		List<SellRecordBO> fbaSellData = sellRecordList.stream()
				.filter(l -> fbaWlList.contains(l.getLywl())).collect(Collectors.toList());
		//--- 其他（oeu与非oeu）的数据处理 ---
		//先把销售的发货日期连上
		Map<String, String> deliveryMap = deliveryGoodsList.stream().distinct()
				.filter(l -> StringUtils.isNotBlank(l.getSheetNumber()))
				.collect(Collectors.toMap(l -> l.getNid() + l.getCpbh() + l.getSheetNumber(), SellRecordBO::getDate,
						(k1, k2) -> k1.compareTo(k2) > 0 ? k1 : k2));
		sellRecordList.stream().distinct().forEach(l -> {
			String key = l.getNid() + l.getCpbh() + l.getSheetNumber();
			if (StringUtils.isNotBlank(deliveryMap.get(key))) {
				l.setDate(deliveryMap.get(key));
			}
		});
		Map<String, List<SellRecordBO>> noFbaSellDataMap = sellRecordList.stream().distinct()
				.filter(l -> !fbaWlList.contains(l.getLywl()) && !l.getDianPu().equals("oboffline")
						&& !("SFA".equals(l.getLywl()) && StringUtils.isBlank(l.getDate())) &&
						//排除店铺不为oeu时，发货数据为空的情况；对应python店铺不为oeu，并且发货NId为空的情况
						(l.getDianPu().equals("oeu") || StringUtils.isNotBlank(l.getDate())))
				.collect(Collectors.groupingBy(l -> l.getNid() + l.getCpbh() + l.getOrderId()));
		List<SellRecordBO> noFbaDeliveryGoods = deliveryGoodsList.stream().distinct()
				.filter(l -> !fbaWlList.contains(l.getLywl()) && !l.getDianPu().equals("oboffline")
						&& !("SFA".equals(l.getLywl()) && StringUtils.isBlank(l.getDate())) &&
						(l.getDianPu().equals("oeu") || StringUtils.isNotBlank(l.getDate())))
				.collect(Collectors.toList());
		//上述说了其他数据的最终orderDate是以发货为准（若发货有取发货中的date，没有则取销售），有可能出现以下情况
		//发货时间在月初，但是销售是在n天/n礼拜前，那么在下面逻辑去匹配销售数据时，匹配不到，所以就需要将该发货数据加入到最终数据集合去
		List<SellRecordBO> addFinalData = new ArrayList<>();
		for (SellRecordBO delivery : noFbaDeliveryGoods) {
			String key = delivery.getNid() + delivery.getCpbh() + delivery.getOrderId();
			List<SellRecordBO> sellList = noFbaSellDataMap.get(key);
			if (StringUtils.isBlank(delivery.getSheetNumber())) {
				continue;
			}
			//有发货记录，用里面的信息
			if (CollectionUtils.isEmpty(sellList)) {
				delivery.setOrderDate(delivery.getDate());
				delivery.setChck(delivery.getWarehouseId());
				delivery.setDate("");
				delivery.setWarehouseId("");
				addFinalData.add(delivery);
				continue;
			}
			for (SellRecordBO sell : sellList) {
				sell.setChck(delivery.getWarehouseId());
				sell.setOrderDate(delivery.getDate());
				sell.setDate("");
				sell.setWarehouseId("");
			}
		}
		if (!CollectionUtils.isEmpty(addFinalData)) {
			sellDeliveryList.addAll(addFinalData);
		}
		if (!CollectionUtils.isEmpty(fbaSellData)) {
			sellDeliveryList.addAll(fbaSellData);
		}
		sellDeliveryList.addAll(noFbaSellDataMap.values().stream()
				.flatMap(List::stream).collect(Collectors.toList()));

		for (SellRecordBO bo : sellDeliveryList) {
			if (bo.getChck().equals("EU2FR1102")) {
				bo.setChck("EU101");
			}
			setRealWhId(bo, placeMatchDictMap);
			if (!bo.getDianPu().equals("oeu")) {
				bo.setCompany(storeMap.get(bo.getDianPu()));
			} else {
				bo.setCompany(oeuOrderMap.get(bo.getOrderId()));
			}
			if (!fbaCountryList.contains(bo.getFromCountry()) && StringUtils.isNotBlank(bo.getRestockMark()) &&
					bo.getRestockMark().equals("FBA")) {
				bo.setFromCountry("DE");
			}
		}
	}

	/**
	 * 设置最终的出货仓库和退货标记
	 *
	 * @param bo                销售数据
	 * @param placeMatchDictMap place匹配字典
	 */
	private void setRealWhId(SellRecordBO bo, Map<String, PlaceMatchDict> placeMatchDictMap) {
		PlaceMatchDict placeMatchDict = placeMatchDictMap.get(bo.getChck());
		if (Objects.nonNull(placeMatchDict)) {
			if (placeMatchDict.getType().equals("ck")) {
				bo.setChck(placeMatchDict.getRealWhId());
			} else {
				if (placeMatchDict.getType().equals("restock")) {
					bo.setChck(placeMatchDict.getRealWhId());
					bo.setRestockMark("restock");
				} else {
					bo.setRestockMark(placeMatchDict.getRealWhId());
				}
			}
		} else {
			bo.setRestockMark("");
		}
	}

	/**
	 * 获取销售补单数据
	 * (流程与getSellDeliveryListByDate一致，仅取的是补单的数据【本地与补单月份的差异数据】)
	 *
	 * @param suppStartDate     补单开始月份
	 * @param suppEndDate       补单结束月份
	 * @param placeMatchDictMap 仓库匹配字段map
	 * @param storeMap          店铺map
	 * @param fbaCountryList    fba国家列表
	 * @return list
	 */
	public List<SellRecordBO> getHisSellDeliveryListByDate(String suppStartDate, String suppEndDate,
														   Map<String, PlaceMatchDict> placeMatchDictMap,
														   Map<String, String> storeMap, List<String> fbaCountryList) {
		List<SellRecordBO> sellDeliveryList = new LinkedList<>();
		List<SellRecordBO> hisSellRecordList = euSourceDataService.getHisSellRecordListByDate(suppStartDate, suppEndDate);  // TODO - 数据源待修改  fa_eu.temp_xsjl  temp_xsjl_delete   temp_xsjl_abnormal  europe.xsjl_2303
		List<String> whIds = euSourceDataService.getWhIdByTimeGet(suppStartDate, suppEndDate);  // TODO - 数据源待修改 europe.ck deliver_goods
		List<SellRecordBO> hisDeliveryGoodsList = euSourceDataService  // TODO - 数据源待修改 fa_eu.temp_xsjl  temp_xsjl_delete  temp_xsjl_abnormal   europe.deliver_goods  deliver_goodssheet  xsjl_2303
				.getHisDeliveryGoodsListByDate(suppStartDate, suppEndDate, whIds);
		this.getEligibleSellDeliveryData(hisSellRecordList, hisDeliveryGoodsList,
				sellDeliveryList, placeMatchDictMap, storeMap, fbaCountryList);
		return sellDeliveryList.stream().distinct().filter(l -> !l.getChck().equals("EU07"))
				.collect(Collectors.toList());

	}

	public List<SellRecordBO> getHisSellDeliveryListByDateDaily(String suppStartDate, String suppEndDate,
														   Map<String, PlaceMatchDict> placeMatchDictMap,
														   Map<String, String> storeMap, List<String> fbaCountryList) {
		List<SellRecordBO> sellDeliveryList = new LinkedList<>();
		List<SellRecordBO> hisSellRecordList = stkSellMapper.getHisSellRecordListByDateDaily(suppStartDate, suppEndDate);  // TODO - 数据源待修改  fa_eu.temp_xsjl  temp_xsjl_delete   temp_xsjl_abnormal  europe.xsjl_2303
		List<String> whIds = stkSellMapper.getWhIdByTimeGetDaily(suppStartDate, suppEndDate);  // TODO - 数据源待修改 europe.ck deliver_goods
		List<SellRecordBO> hisDeliveryGoodsList = stkSellMapper  // TODO - 数据源待修改 fa_eu.temp_xsjl  temp_xsjl_delete  temp_xsjl_abnormal   europe.deliver_goods  deliver_goodssheet  xsjl_2303
				.getHisDeliveryGoodsListByDateDaily(suppStartDate, suppEndDate, whIds); // TODO - 这里使用到了fa_eu和rxh的数据库，在后面的话，他一定会出问题，如果使用数据中心的链接
		this.getEligibleSellDeliveryData(hisSellRecordList, hisDeliveryGoodsList,
				sellDeliveryList, placeMatchDictMap, storeMap, fbaCountryList);
		return sellDeliveryList.stream().distinct().filter(l -> !l.getChck().equals("EU07"))
				.collect(Collectors.toList());

	}

	/**
	 * 移除销售发货数据中历史已存在相同sheetNumber数据
	 *
	 * @param sellDeliveryList 销售发货数据
	 */
	public void checkSheetNumber(List<SellRecordBO> sellDeliveryList) {
		Set<String> xsSheetNumberSet = tempXsjlMapper.selectDistinctSheetNumber();  // TODO - 数据源待修改 fa_eu.temp_xsjl
		List<SellRecordBO> removeList = new LinkedList<>();
		for (SellRecordBO sell : sellDeliveryList) {
			if (xsSheetNumberSet.contains(sell.getSheetNumber())) {
				removeList.add(sell);
			}
		}
		if (!CollectionUtils.isEmpty(removeList)) {
			sellDeliveryList.removeAll(removeList);
		}
	}

	public void checkSheetNumberDaily(List<SellRecordBO> sellDeliveryList,String startDate) {
		Set<String> xsSheetNumberSet = tempXsjlMapper.selectDistinctSheetNumberDaily(startDate);  // TODO - 数据源待修改 fa_eu.temp_xsjl
		List<SellRecordBO> removeList = new LinkedList<>();
		for (SellRecordBO sell : sellDeliveryList) {
			if (xsSheetNumberSet.contains(sell.getSheetNumber())) {
				removeList.add(sell);
			}
		}
		if (!CollectionUtils.isEmpty(removeList)) {
			sellDeliveryList.removeAll(removeList);
		}
	}

	public List<SellRecordBO> getlywlIsFbaReturnList(String startDate, String endDate) {
		return euSourceDataService.getlywlIsFbaReturnList(startDate, endDate);
	}
}
